﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BobcatMultiTouch;
using System.Drawing;
using BobcatUtility;

namespace CNShapeEditor
{
    /// <summary>
    /// This action lets you zoom (or shrink) the picture using two input
    /// sources and a pinch-or-stretch gesture. It zooms the picture according to 
    /// the pinch-or-zoom movement and also moves the picture origin to keep
    /// the top input point over the same screen point as the zoom occurs.
    /// </summary>
    class Action_MultiTouchZoomPicture : Action
    {
        #region Public methods

        /// <summary>
        /// Called to set up the action.
        /// </summary>
        public override void initialize()
        {
        }

        /// <summary>
        /// Returns the user-readabale description of the action.
        /// </summary>
        public override string getDescription()
        {
            return "Zoom picture (multi-touch)";
        }

        /// <summary>
        /// We do not support undo for this action (as it just affects the view, not the picture itself).
        /// </summary>
        public override bool supportsUndo()
        {
            return false;
        }

        /// <summary>
        /// Not supported for this action (as it only affects the view).
        /// </summary>
        public override void undo()
        {
        }

        /// <summary>
        /// Not supported for this action (as it only affects the view).
        /// </summary>
        public override void redo()
        {
        }

        /// <summary>
        /// Called when we receive a touch-down event.
        /// </summary>
        public override void onTouchDown(TouchArgs touchArgs)
        {
            // We see if we've got two active points...
            IList<TouchArgs> listActiveTouches = m_ShapeEditorControl.MTIC.getActiveTouches();
            if (listActiveTouches.Count != 2)
            {
                return;
            }

            // We note the two initial points and the distance between them...
            Point p1 = listActiveTouches[0].ClientPosition;
            Point p2 = listActiveTouches[1].ClientPosition;
            m_dInitialDistance = Utility.getDistance(p1, p2);

            // We store the top point for use later...
            Point topPoint = (p1.Y < p2.Y) ? p1 : p2;
            m_InitialTopPoint_ShapeCoords = m_ShapeViewerControl.clientPointToShapePoint(topPoint);

            // We store the initial zoom factor of the control...
            m_fInitialZoomFactor = m_ShapeViewerControl.ZoomFactor;

            m_bActionUnderway = true;
        }

        /// <summary>
        /// Called when we get a touch-move event.
        /// </summary>
        public override void onTouchMove(TouchArgs touchArgs)
        {
            // Has the action really started? As this action needs two touch sources, we can
            // get movements from the first touch source before the second one has been 
            // detected...
            if (m_bActionUnderway == false)
            {
                return;
            }

            // We should still have two active points...
            IList<TouchArgs> listActiveTouches = m_ShapeEditorControl.MTIC.getActiveTouches();
            if (listActiveTouches.Count != 2)
            {
                return;
            }

            // We find the new distance between them and set the new zoom factor...
            Point p1 = listActiveTouches[0].ClientPosition;
            Point p2 = listActiveTouches[1].ClientPosition;
            double dDistance = Utility.getDistance(p1, p2);

            // We calculate and set the new zoom-factor...
            double dZoomFactor = m_fInitialZoomFactor * (dDistance / m_dInitialDistance);
            m_ShapeViewerControl.ZoomFactor = (float)dZoomFactor;

            // We want to keep the top touch point over the same shape-point that it
            // started at, so we may want to move the origin...
            Point topPoint_Client = (p1.Y < p2.Y) ? p1 : p2;
            PointF topPoint_Shape = m_ShapeViewerControl.clientPointToShapePoint(topPoint_Client);
            float fXOffset = m_InitialTopPoint_ShapeCoords.X - topPoint_Shape.X;
            float fYOffset = m_InitialTopPoint_ShapeCoords.Y - topPoint_Shape.Y;
            PointF origin = m_ShapeViewerControl.Origin;
            origin.X += fXOffset;
            origin.Y += fYOffset;
            m_ShapeViewerControl.Origin = origin;
        }

        /// <summary>
        /// Called when we get a touch-up event.
        /// </summary>
        public override void onTouchUp(TouchArgs touchArgs)
        {
            // The action has completed...
            raiseActionCompletedEvent();
        }

        #endregion

        #region Private data

        // The zoom-factor at the start of the zoom...
        private float m_fInitialZoomFactor = 1f;

        // The initial position of the top input source in shape-coordinates...
        private PointF m_InitialTopPoint_ShapeCoords = new PointF();

        // The initial distance between the two input points (in client-coordinates)...
        private double m_dInitialDistance = 0.0;

        // Tells us whether the action has started (i.e. we've seen two touches)...
        private bool m_bActionUnderway = false;

        #endregion
    }
}
